#include "catalog.h"
#include "query.h"
#include "index.h"

// Implements the index select operator
Status Operators::IndexSelect(const string & result,      // name of the output relation
  	                      const int projCnt,          // number of attributes in the projection
                              const AttrDesc projNames[], // The projection list (as AttrDesc)
                              const AttrDesc *attrDesc,   // the attribute in the selection predicate
                              const Operator op,          // the predicate operation
                              const void *attrValue,      // a pointer to the literal value in the predicate
                              const int reclen)           // length of a tuple in the result relation
{
  cout << "Algorithm: Index Select" << endl;


	//error checking stuff
	if(attrValue == NULL)
	{
		return NO_ATTR_VAL;
	}

	
	Status index_status;
	Index idx(attrDesc->relName, attrDesc->attrOffset, attrDesc->attrLen, (Datatype)attrDesc->attrType,
		false, index_status);

	if(index_status != OK)
		return index_status;
	
	Status heap_status;
	HeapFileScan heapFileRead(attrDesc->relName, heap_status);

	if(heap_status != OK)
		return heap_status;


	Status heap_result_status;
	HeapFile heapFileResult(result, heap_result_status);
	
	if(heap_result_status != OK)
		return heap_result_status;

	Status index_start_scan = idx.startScan(attrValue);
	
	if(index_start_scan != OK)
		return index_start_scan;

	RID old_rid;
	RID new_rid;
	Record rec;

	//get the info on this relation
	AttrDesc *attrDescs;
	int attrDescsCnt;
	attrCat->getRelInfo(projNames[0].relName, attrDescsCnt, attrDescs);
	
	int result_len = 0;
	//new plan, don't need to check values but we do need to copy over the record into a new rec
	for(int i = 0; i < projCnt; i++)
	{
		result_len += projNames[i].attrLen;
	}

	while(true)
	{
		
		Status index_scan_status = idx.scanNext(old_rid);
		
		if(index_scan_status == NOMORERECS)
			return OK;

		if(index_scan_status != OK)
			return index_scan_status;

		Status random_record_read = heapFileRead.getRandomRecord(old_rid, rec);	
		if(random_record_read != OK)
			return random_record_read;

		Record result_rec;
		result_rec.length = result_len;
		result_rec.data = malloc(result_len);


		int result_offset = 0;
		//loop through to fill in data
		for(int i = 0; i < projCnt; i++)
		{
			for(int j = 0; j < attrDescsCnt; j++)
			{
				if(strcmp(projNames[i].attrName, attrDescs[j].attrName) == 0)
				{
					if(projNames[i].attrLen + result_offset > result_rec.length)
					{
						return ATTRTOOLONG;
					}
					memcpy((char*)result_rec.data + result_offset, 		
						(char*)rec.data + attrDescs[j].attrOffset, projNames[i].attrLen);
					
					result_offset += projNames[i].attrLen;
					break;
				}
				else if(j == (attrDescsCnt -1))
				{
					return ATTRNOTFOUND;
				}
				
			}
		}
		Status insert_record = heapFileResult.insertRecord(result_rec, new_rid);
		if(insert_record != OK)
			return insert_record;
		
		free(result_rec.data);
	}
	Status end_scan = idx.endScan();

	if(end_scan != OK)
		return end_scan;

  return OK;
}

